#include	"../utils/tinyxml2.h"

extern "C" {
#include	<luajit.h>
#include	<lualib.h>
#include	<lauxlib.h>
}

namespace {

    static void ParseNode(lua_State * lua, const tinyxml2::XMLNode * node) {        
        const tinyxml2::XMLElement * elem = node->ToElement();
        lua_newtable(lua);

        // Set node's name
        lua_pushstring(lua, elem->Name());
        lua_setfield(lua, -2, "name");

        // Set node's text
        const char * text = elem->GetText();
        if (text) {
            lua_pushstring(lua, text);
            lua_setfield(lua, -2, "value");
        }
        
        // Parse all attributes
        const tinyxml2::XMLAttribute * attr = elem->FirstAttribute();
        lua_newtable(lua);
        while (attr) {
            lua_pushstring(lua, attr->Name());
            lua_pushstring(lua, attr->Value());
            lua_settable(lua, -3);

            attr = attr->Next();
        }
        lua_setfield(lua, -2, "attr");

        // Parse all children
        const tinyxml2::XMLNode * child = elem->FirstChildElement();
        int idx = 1;
        lua_newtable(lua);
        while (child) {
            ParseNode(lua, child);
            lua_rawseti(lua, -2, idx);

            idx++;
            child = child->NextSiblingElement();
        }
        lua_setfield(lua, -2, "children");
    }

    static int Parse(lua_State * lua) {
        size_t len = 0;
        const char * content = lua_tolstring(lua, 1, &len);

        tinyxml2::XMLDocument doc;
        tinyxml2::XMLError err = doc.Parse(content, len);
        if (err != tinyxml2::XML_SUCCESS) {
            luaL_error(lua, doc.ErrorName());
            return 0;
        }

        ParseNode(lua, doc.FirstChildElement());
        return 1;
    }
}

void RegisterApi_XML(lua_State * lua) {
    lua_newtable(lua);
    lua_pushcfunction(lua, &Parse);
    lua_setfield(lua, -2, "parse");
    lua_setglobal(lua, "xml");
}
